package com.taoym.voucher.job.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.taoym.voucher.common.enums.QuartzJobGroupEnum;
import com.taoym.voucher.common.response.ResponseStatusCode;
import com.taoym.voucher.common.utils.ExceptionCore;
import com.taoym.voucher.common.utils.SecureUtils;
import com.taoym.voucher.job.config.quartz.TriggerComponent;
import com.taoym.voucher.job.domain.SysQuartzJob;
import com.taoym.voucher.job.domain.SysUser;
import com.taoym.voucher.job.entity.dto.AddJobDTO;
import com.taoym.voucher.job.entity.vo.GetQuartzJobVO;
import com.taoym.voucher.job.mapper.SysQuartzJobMapper;
import com.taoym.voucher.job.mapper.SysUserMapper;
import com.taoym.voucher.job.service.JobService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @coder taoym
 * @datetime 2021/6/27 13:22
 * @desc 任务服务接口实现类
 */
@Service
public class JobServiceImpl implements JobService {
    @Resource
    private SysQuartzJobMapper sysQuartzJobMapper;
    @Autowired
    private Scheduler scheduler;
    @Resource
    private SysUserMapper sysUserMapper;

    @Override
    public Integer addJob(AddJobDTO data) {

        Integer count = sysQuartzJobMapper.selectCount(new QueryWrapper<SysQuartzJob>()
                .eq("group_code", data.getGroupCode()));
        if (count > 0) {
            throw new ExceptionCore(ResponseStatusCode.JOB_IS_EXIST);
        }

        QuartzJobGroupEnum groupEnum = QuartzJobGroupEnum.getMsg(data.getGroupCode());
        if (ObjectUtils.isEmpty(groupEnum)) {
            return 0;
        }
        SysQuartzJob sysQuartzJob = new SysQuartzJob();
        sysQuartzJob.setJobName(data.getJobName());
        sysQuartzJob.setCron(data.getCron());
        sysQuartzJob.setGroupCode(data.getGroupCode());
        sysQuartzJob.setGroupName(groupEnum.getMsg());
        sysQuartzJob.setJobClassPath(groupEnum.getClassPath());
        sysQuartzJob.setUpdateTime(LocalDateTime.now());
        return sysQuartzJobMapper.insert(sysQuartzJob);
    }

    @Override
    public List<GetQuartzJobVO> quartzJobs() {
        List<SysQuartzJob> sysQuartzJobs = sysQuartzJobMapper.selectList(new QueryWrapper<>());
        if (CollectionUtils.isEmpty(sysQuartzJobs)) {
            return null;
        }
        return JSON.parseArray(JSON.toJSONString(sysQuartzJobs), GetQuartzJobVO.class);
    }

    @Override
    public Integer startJob(Integer id) {
        SysQuartzJob sysQuartzJob = sysQuartzJobMapper.selectById(id);
        List<SysUser> sysUsers = sysUserMapper.selectList(new QueryWrapper<>());
        assert !CollectionUtils.isEmpty(sysUsers);
        SysUser sysUser = sysUsers.get(0);
        if (ObjectUtils.isEmpty(sysUser.getApiKey())) {
            throw new ExceptionCore(ResponseStatusCode.SYS_DEPLOY_IS_NOT_COMPLETE);
        }
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("apiKey", sysUser.getApiKey());
        jobDataMap.put("appId", SecureUtils.decrypt(sysUser.getAppId()));
        jobDataMap.put("appSecret", SecureUtils.decrypt(sysUser.getAppSecret()));
        jobDataMap.put("distRate", sysUser.getDistRate());
        jobDataMap.put("teamRate", sysUser.getTeamRate());

        JobKey jobKey = JobKey.jobKey(sysQuartzJob.getJobName() + ":" + sysQuartzJob.getGroupCode());
        Class<? extends Job> aClass = null;
        try {
            aClass = (Class<? extends Job>) Class.forName(sysQuartzJob.getJobClassPath());
        } catch (ClassNotFoundException e) {
            throw new ExceptionCore(ResponseStatusCode.JOB_CLASS_IS_NOT_FIND);
        }

        JobDetail jobDetail = JobBuilder.newJob(aClass).withIdentity(jobKey).storeDurably().build();
        Trigger trigger = TriggerComponent.cronTrigger(sysQuartzJob.getCron(), jobDataMap, sysQuartzJob.getJobName(), sysQuartzJob.getGroupName());
        try {
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new ExceptionCore(ResponseStatusCode.JOB_IS_FAIL);
        }
        sysQuartzJob.setStatus(1);
        sysQuartzJob.setUpdateTime(LocalDateTime.now());
        return sysQuartzJobMapper.updateById(sysQuartzJob);
    }

    @Override
    public Integer stopJob(Integer id) {
        SysQuartzJob sysQuartzJob = sysQuartzJobMapper.selectById(id);
        JobKey jobKey = JobKey.jobKey(sysQuartzJob.getJobName() + ":" + sysQuartzJob.getGroupCode());
        try {
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new ExceptionCore(ResponseStatusCode.JOB_IS_FAIL);
        }
        sysQuartzJob.setStatus(2);
        sysQuartzJob.setUpdateTime(LocalDateTime.now());
        return sysQuartzJobMapper.updateById(sysQuartzJob);
    }

    @Override
    public Integer proceed(Integer id) {
        SysQuartzJob sysQuartzJob = sysQuartzJobMapper.selectById(id);
        JobKey jobKey = JobKey.jobKey(sysQuartzJob.getJobName() + ":" + sysQuartzJob.getGroupCode());
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new ExceptionCore(ResponseStatusCode.JOB_IS_FAIL);
        }
        sysQuartzJob.setStatus(1);
        sysQuartzJob.setUpdateTime(LocalDateTime.now());
        return sysQuartzJobMapper.updateById(sysQuartzJob);
    }

    @Override
    public Integer delete(Integer id) {
        SysQuartzJob sysQuartzJob = sysQuartzJobMapper.selectById(id);
        JobKey jobKey = JobKey.jobKey(sysQuartzJob.getJobName() + ":" + sysQuartzJob.getGroupCode());
        try {
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new ExceptionCore(ResponseStatusCode.JOB_IS_FAIL);
        }
        return sysQuartzJobMapper.deleteById(id);
    }

    @Override
    public Integer resetJobStatus(Integer id) {
        SysQuartzJob sysQuartzJob = new SysQuartzJob();
        sysQuartzJob.setId(id);
        sysQuartzJob.setStatus(0);
        return sysQuartzJobMapper.updateById(sysQuartzJob);
    }
}
